﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using FisheryPlatform.SiteConfig.FileStore;
using FisheryPlatform.SiteConfig;

namespace FisheryPlatform.Bussiness.FileStore
{
    public abstract class FileUploadProviderBase : IFileUploadProvider
    {
        #region protected

        protected FileServerMap FileServerMap = null;
        protected FileServer FileServer = null;
        protected UploadFileEntity UploadFileEntity = null;
        protected string ServiceType = null;
        protected string MimeItemKey = "image";

        #endregion

        public void Init(UploadFileEntity entity, bool validateMime, string serviceType, string mimeItemKey)
        {
            #region
            if (string.IsNullOrEmpty(entity.Id))
            {
                throw new Exception("UploadFileEntity Id 不能为空；");
            }
            ServiceType = serviceType;
            MimeItemKey = mimeItemKey;
            UploadFileEntity = entity;

            MatchFileServer();
            if (validateMime)
                ValidateFileMime();
            GenerateStorePathAndPublishUrl();
            #endregion
        }

        public virtual string FileServerRootPath
        {
            get;
            set;
        }

        protected virtual void MatchFileServer()
        {
            #region

            FileServerMap = SiteConfigManager.FileServerMapList.GetFileServerMap(UploadFileEntity.UploadDate, ServiceType);
            if (FileServerMap == null)
            {
                throw new Exception("查询不到文件服务器匹配节点");
            }
            else
            {
                FileServer = SiteConfigManager.FileServerList.GetFileServer(FileServerMap.MapName);
                if (FileServer == null)
                {
                    throw new Exception("根据节点‘" + FileServerMap.MapName + "’查询不到服务器");
                }
            }
            FileServerRootPath = FileServer.RootPath;
            #endregion
        }

        protected virtual void ValidateFileMime()
        {
            #region
            var extName = Path.GetExtension(UploadFileEntity.ClientFileName).ToLower();
            var flag = false;
            MimeItem mimeItem = FileServer.MimeItemList.GetMimeItem(MimeItemKey);
            if (mimeItem != null)
            {
                flag = mimeItem.MimeTypeList.Split(';').ToList<string>().Contains(extName);
                if (flag == false)
                {
                    throw new Exception("上传的文件扩展名未知" + extName);
                }
            }
            #endregion
        }

        public virtual void Save()
        {
            #region
            if (UploadFileEntity.Content.Length <= 0)
                return;
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);

                string dirPath = Path.GetDirectoryName(UploadFileEntity.ServerStorePath);
                if (!System.IO.Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }

                using (FileStream writer = File.Open(UploadFileEntity.ServerStorePath, FileMode.OpenOrCreate))
                {
                    writer.Write(UploadFileEntity.Content, 0, UploadFileEntity.Content.Length);
                    writer.Flush();
                    writer.Close();
                }
            }
            #endregion
        }

        public virtual void Delete()
        {
            #region
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);

                if (File.Exists(UploadFileEntity.ServerStorePath))
                {
                    File.Delete(UploadFileEntity.ServerStorePath);
                }
            }
            #endregion
        }

        /// <summary>
        /// 文件路径
        /// </summary>
        public virtual string Read(string filePath)
        {
            #region
            var result = "";
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);

                if (File.Exists(filePath))
                {
                    using (FileStream reader = File.Open(filePath, FileMode.OpenOrCreate))
                    {
                        var content = new byte[reader.Length];
                        reader.Read(content, 0, content.Length);
                        reader.Close();
                        result = System.Text.Encoding.Default.GetString(content);
                    }
                }
            }
            return result;
            #endregion
        }

        public virtual byte[] ReadBytes(string filePath)
        {
            #region
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);

                if (File.Exists(filePath))
                {
                    using (FileStream reader = File.Open(filePath, FileMode.OpenOrCreate))
                    {
                        var content = new byte[reader.Length];
                        reader.Read(content, 0, content.Length);
                        reader.Close();
                        return content;
                    }
                }
            }
            return new byte[]{};
            #endregion
        }

        /// <summary>
        /// 将指定的文件直接写入 HTTP 响应输出流
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="response"></param>
        public virtual bool Read(string fileName, string filePath, HttpResponse Response)
        {
            #region
            var flag = false;
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);

                //if (File.Exists(filePath))
                //{
                //    response.TransmitFile(filePath);
                //    flag = true;
                //}
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath);
                if (fileInfo.Exists == true)
                {
                    Response.ContentType = "application/octet-stream";
                    Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName));
                    const long ChunkSize = 102400;
                    byte[] buffer = new byte[ChunkSize];
                    Response.Clear();
                    System.IO.FileStream fileStream = System.IO.File.OpenRead(filePath);
                    long dataTotalLength = fileStream.Length;
                    int readDataLength = 0;
                    while (dataTotalLength > 0 && Response.IsClientConnected)
                    {
                        readDataLength = fileStream.Read(buffer, 0, Convert.ToInt32(ChunkSize));
                        Response.OutputStream.Write(buffer, 0, readDataLength);
                        Response.Flush();
                        dataTotalLength = dataTotalLength - readDataLength;
                    }
                    Response.Close();

                    flag = true;
                }
            }
            return flag;
            #endregion
        }

        /// <summary>
        /// 文件移动
        /// </summary>
        public virtual bool MoveTo(string destFileName)
        {
            #region
            var flag = false;
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);
                string dirPath = Path.GetDirectoryName(UploadFileEntity.ServerStorePath);
                if (!System.IO.Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(UploadFileEntity.ServerStorePath);
                if (fileInfo.Exists == true)
                {
                    fileInfo.MoveTo(destFileName);
                    flag = true;
                }
            }
            return flag;
            #endregion
        }

        /// <summary>
        /// 文件移动
        /// </summary>
        /// <param name="oldFileName">要移动的文件包括文件路径</param>
        /// <param name="newFileName">目标位置包括文件名</param>
        /// <returns></returns>
        public virtual bool Move(string oldFileName, string newFileName)
        {
            #region
            var flag = false;
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);
                string dirPath = Path.GetDirectoryName(newFileName);
                if (!System.IO.Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(oldFileName);
                if (fileInfo.Exists == true)
                {
                    fileInfo.MoveTo(newFileName);
                    flag = true;
                }
            }
            return flag;
            #endregion
        }

        /// <summary>
        /// 将原目录中所有文件移动到目的目录
        /// </summary>
        /// <param name="sourceDir">原目录</param>
        /// <param name="desdir">目的目录</param>
        /// <returns>true成功,false失败</returns>
        public virtual bool MoveFiles(string sourceDir, string desdir, List<string> files)
        {
            #region
            var flag = false;
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);

                if (!System.IO.Directory.Exists(desdir))
                {
                    Directory.CreateDirectory(desdir);
                }
                if (Directory.Exists(sourceDir))
                {
                    string[] Files = Directory.GetFiles(sourceDir);
                    foreach (string file in Files)
                    {
                        if (files.Contains(Path.GetFileName(file)))
                        {
                            string desFileName = desdir + "\\" + Path.GetFileName(file);
                            File.Move(file, desFileName);
                        }

                    }
                    flag = true;
                }

            }
            return flag;
            #endregion
        }

        public virtual List<string> GetAllFileName(string smartID)
        {
            #region
            List<string> lst = new List<string>();
            using (ImpersonateUser iu = new ImpersonateUser())
            {
                ImpersonateUser.ValidUser(iu, FileServer.Indentity);
                string SoureDir = string.Format("{0}\\temp\\{1}", FileServerRootPath, smartID);
                if (Directory.Exists(SoureDir))
                {
                    string[] fileNames = Directory.GetFiles(SoureDir);
                    foreach (string file in fileNames)
                    {
                        lst.Add(Path.GetFileName(file));
                    }
                }
            }
            return lst;
            #endregion
        }

        /// <summary>
        /// \{yyyyMMdd}\{Id}.{ExtensionName}
        /// </summary>
        protected virtual void GenerateStorePathAndPublishUrl()
        {
            #region
            /*\{yyyyMMdd}\{id}.{ExtensionName}*/
            var result = string.Format(@"\{0}\{1}{2}", UploadFileEntity.UploadDate.ToString("yyyyMMdd"), UploadFileEntity.Id, Path.GetExtension(UploadFileEntity.ClientFileName));

            UploadFileEntity.ServerStorePath = FileServer.RootPath + result;
            UploadFileEntity.ServerStoreRelativePath = FileServer.PublishUrl + result;
            UploadFileEntity.PublishUrl = FileServer.PublishUrl;
            UploadFileEntity.PublishUrlPath = result.Replace('\\', '/');
            #endregion
        }
    }
}
